module mixColumns
(
//OUTPUTS
output [31:0] mix_col,
//INPUTS
input [31:0] col,
input enc_dec
);

wire [31:0] mix_col_enc;
wire [31:0] mix_col_dec;
 
assign mix_col = enc_dec ? mix_col_enc : mix_col_enc ^ mix_col_dec;

mix_col_enc MIX_ENC
(
  .mix_col(mix_col_enc),
  .col_in(col)
);
mix_col_dec MIX_DEC
(
  .mix_col(mix_col_dec),
  .col_in(col)
);
endmodule

//=====================================================================================
// 1)  Inverse Mix Column Operation
//=====================================================================================
module inv_mixColumns
(
//OUTPUTS
output [31:0] mix_col,
//INPUTS
input [31:0] col
);

wire [31:0] mix_col_enc;
wire [31:0] mix_col_dec;
 
assign mix_col = mix_col_enc ^ mix_col_dec;

mix_col_enc MIX_ENC
(
  .mix_col(mix_col_enc),
  .col_in(col)
);
mix_col_dec MIX_DEC
(
  .mix_col(mix_col_dec),
  .col_in(col)
);
endmodule

//=====================================================================================
// 2)  Direct Mix Column Operation
//=====================================================================================
module mix_col_enc
(
  //OUTPUTS
  output [31:0] mix_col,
  //INPUTS
  input [31:0] col_in 
);
`include "gf_functions.vh"

wire [7:0] col [3:0];

generate
  genvar i;
  for(i = 0; i < 4; i = i + 1)
    begin
      assign col[3 - i] = col_in[8*(i + 1) - 1 : 8*i]; 
    end
endgenerate

  assign mix_col[ 7: 0] = mix_col_pol(col[3] ^ col[2], col[1] ^ col[0], col[2]);
  assign mix_col[15: 8] = mix_col_pol(col[2] ^ col[1], col[1] ^ col[0], col[3]);
  assign mix_col[23:16] = mix_col_pol(col[1] ^ col[0], col[3] ^ col[2], col[0]);
  assign mix_col[31:24] = mix_col_pol(col[0] ^ col[3], col[3] ^ col[2], col[1]);

endmodule

//=====================================================================================
// 3)  Partial Inverse Mix Column Operation
//=====================================================================================
module mix_col_dec
(
  //OUTPUTS
  output [31:0] mix_col,
  //INPUTS
  input [31:0] col_in 
);

`include "gf_functions.vh"

wire [7:0] col [3:0];

generate
  genvar i;
  for(i = 0; i < 4; i = i + 1)
    begin
      assign col[3 - i] = col_in[8*(i + 1) - 1 : 8*i]; 
    end
endgenerate

wire [7:0] y0, y1, y2;

assign y0 = aes_mult_04(col[2] ^ col[0]);
assign y1 = aes_mult_04(col[3] ^ col[1]);
assign y2 = aes_mult_02(y1 ^ y0);

assign mix_col[ 7: 0] = y2 ^ y1; 
assign mix_col[15: 8] = y2 ^ y0;
assign mix_col[23:16] = y2 ^ y1;
assign mix_col[31:24] = y2 ^ y0;

endmodule
